unit MasterPiece;

interface

uses
    Winapi.Windows,
    Vcl.Graphics,
    Vcl.Dialogs,

    Vcl.Forms,
    Vcl.Controls,
    Classes,
    System.SysUtils,
    Generics.Collections,
    Opengl,
    GLFrames,
    gblur2,
    Point,
    Bitmap2,
    stroke,
    colors,
    Files,

    GLCadencer,
    GLSimpleNavigation,
    GLScene,
    GLObjects,
    GLWin32Viewer,
    GLSLShader,    VectorLists, VectorTypes, VectorGeometry, GLMaterial,
    GLVectorFileObjects;


type
    TMasterPiece = class
        protected

        private
            pathImageSource : string;
        public
            Scene1 : TGLScene;
            SceneViewer1 : TGLSceneViewer;
            Camera1 : TGLCamera;
            Cube1 : TGLCube;
            sprite1 : TGLsprite;
            plane1 : TGLplane;
            myShader: TGLSLShader;
            GLSimpleNavigation1: TGLSimpleNavigation;
            GLCadencer1: TGLCadencer;
            MaterialLibrary: TGLMaterialLibrary;

            ratio : single;
            LightSource1 : TGLLightSource;
            originalPicture : Tpicture;
            original : TBitmap2;
            reference : TBitmap2;
            difference : TBitmap2;
            h,w : integer;
            strokes : TList; //essayer un Tlist<TStroke> plus tard;
            constructor Create(Sender: Tform; pathSource : string);
            procedure Diff(source1:TGLFrame);
            procedure GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double);
            procedure GLSLShaderApply(Shader: TGLCustomGLSLShader);
            procedure AfficherTemps(action: string; tic: integer);
            procedure QuatreCoins();
            procedure AppliquerFlou(rayon:integer);
            function GetColor(image : TBitmap2;  var x : integer; var y : integer) : TRGBA;
            function LocalError(var x , y, xMax, yMax, rayon : integer):integer;
            function PeindreUneCouche(canvas : TGLFrame; rayon : integer) : byte;
            function Peindre(canvas : TGLFrame; rayon : array of integer): byte;
    end;
implementation

constructor TMasterPiece.Create(Sender: Tform;pathSource : string);
var
    a : integer;

begin
    pathImageSource := pathSource;
    Scene1:=TGLScene.Create(Sender);
    SceneViewer1:=TGLSceneViewer.Create(Sender);


    originalPicture := TPicture.Create;
    originalPicture.LoadFromFile(pathSource);

    ratio := originalpicture.Width/originalpicture.Height;

    plane1:=TGLPlane(Scene1.Objects.AddNewChild(TGLplane));
    plane1.Direction.SetVector(0,0,1);
    plane1.Height:= 1;
    plane1.Width:= plane1.Width*ratio;

    //plane1.material.Texture.Image.LoadFromFile(pathSource);
    //materialLibrary.Create(sender);
    //MaterialLibrary.AddTextureMaterial('specular','c:\a.jpg');
    //MaterialLibrary.LibMaterialByName('maPhoto').Shader:= myshader;
    //MaterialLibrary.LibMaterialByName('maPhoto').Material.Texture.Image.LoadFromFile('c:\a.jpg');
    //plane1.Material.MaterialLibrary := MaterialLibrary;
    //plane1.Material.Texture.Disabled := False ;

    LightSource1:=TGLLightSource(Scene1.Objects.AddNewChild(TGLLightSource));
    LightSource1.Position.SetPoint(10,10,10);

    Camera1:=TGLCamera(Scene1.OBJECTS.AddNewChild(TGLCamera));
    Camera1.Position.SetPoint(0,0,2);

    with SceneViewer1 do
    begin
       Parent:=sender; //don't forget this line
       Left:=0;
       Top:=0;
       SceneViewer1.Height:= 300;
       SceneViewer1.Width:= trunc(SceneViewer1.Height*ratio);
       Camera:=Camera1; //finally assign camera
    end;

    //GLSLShader := TGLSLShader.Create(GLSLTestForm);
    //GLSLShader.LoadShaderPrograms('c:\$tfe\Shaders/shader.Vert', 'c:\$tfe\Shaders/shader.Frag');
    //GLSLShader.Enabled := True;
    //myshader.LoadShaderPrograms('c:\$tfe\Shaders/rien.Vert', 'c:\$tfe\Shaders/Tout Rose.Frag');
    //myshader.Enabled := True;
    //GLSLShader.Enabled := True;
    //GLSLShader.LoadShaderPrograms('Shaders/Shader.Vert', 'Shaders/Shader.Frag');
    //GLSLShader.Enabled := True;
    //myshader.OnApply := GLSLShaderApply;

    //GLSimpleNavigation1:= TGLSimpleNavigation.Create(sender);
    //GLSimpleNavigation1.GLSceneViewer :=   SceneViewer1;
    //GLSimpleNavigation1.GLSceneViewer.Camera :=  Camera1;

    //GLCadencer1:= TGLCadencer.Create(sender);
    //GLCadencer1.Scene :=  scene1;
    //GLCadencer1.OnProgress  := GLCadencer1Progress;
end;

procedure TMasterPiece.AfficherTemps(action: string; tic: integer);
var
  tac, dt:integer;
begin
  tac:=Gettickcount;
  dt:=tac-tic;
  ShowMessage(action +': '+ IntToStr(dt) +' ms');
end;

procedure TMasterPiece.GLSLShaderApply(Shader: TGLCustomGLSLShader);
begin
  with Shader do
  begin
    Param['DiffuseColor'].AsVector4f := VectorMake(1, 1, 1, 1);
    Param['AmbientColor'].AsVector4f := VectorMake(0.2, 0.2, 0.2, 1);
    Param['LightIntensity'].AsVector1f := 1;
    Param['MainTexture'].AsTexture2D[0] := MaterialLibrary.LibMaterialByName('Earth').Material.Texture;
  end;
end;

procedure TMasterPiece.GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double);
    begin
        SceneViewer1.Invalidate;
    end;

function TMasterPiece.LocalError( var x , y, xMax, yMax, rayon : integer):integer;
    var
        i, j, dMAx : integer;
        row : PBGRss;
    begin
        dMax := 0;
        result := 0;
        for j := (y - (rayon div 2)) to (y - (rayon div 2)) do
        begin
            row[j] := difference.Scanline[j];
            for i := (x - (rayon div 2)) to (x + (rayon div 2)) do
            begin
                if row[j][i].r > dMax then
                begin
                    dMax := row[j][i].r;
                    xMax := i;
                    yMax := j;
                end;
                Inc(result, row[j][i].r);
            end;
        end;
        result := result div (rayon * rayon);
    end;

procedure TMasterPiece.Diff(source1:TGLFrame);
var
   i,j, dr, db, dg, d : integer;
   fd : extended;
   rows1 : PRGBAss;
   rows2 : PBGRss;
   pbuf : pointer;
   y : integer;
   p1, p2 : pointer;
begin
    difference := TBitmap2.Create;
    difference.CopyCanvas(original, false);
    difference.PixelFormat:= pf32Bit;
    GetMem( pbuf, reference.Width * reference.Height * 4); //reserve memoire de la taille
    glReadPixels( 0, 0, source1.Width, source1.Height, GL_RGBA, GL_UNSIGNED_BYTE, pbuf);

    for y := 0 to (reference.Height -1) do
    begin
        p1 := difference.ScanLine[y];
        p2 := pointer(integer(pbuf) + ((reference.Height-1-y) * difference.Width * 4));//attention swith B et R
        CopyMemory(p1, p2, difference.Width * 4);
    end;
    FreeMem(pbuf);
    for j := 0 to difference.Height-1 do
    begin
        rows1[j] := difference.Scanline[j];
        rows2[j] := reference.Scanline[j];
        for i := 0 to difference.Width-1 do
        begin
            dr := rows1[j][i].r-rows2[j][i].r;
            dg := rows1[j][i].g-rows2[j][i].g;
            db := rows1[j][i].b-rows2[j][i].b;
            fd := sqrt(dr*dr + db*db + dg*dg);
            d := abs(round(fd));
            rows1[j][i].r := 0;
            rows1[j][i].g := 0;
            rows1[j][i].b := d;
        end;
    end;{}
end;

Procedure TMasterPiece.QuatreCoins();
var
    i, j, k : integer;
    paths : array of TPath;
    colors : array of TRGBA;
    row : PBGRs;
begin
    strokes := TList.Create;
    //SetLength(strokes, 4);
    SetLength(paths,4, 1);  //4 paths(coins) d'un point)
    SetLength(colors, 4);   // 4 couleurs (coins)
        j:= original.height-1;
        k:= original.Width-1;
        paths[0][0] := TPoint.Create(0,0,0);    //creer les 4 chemins d'un point
        paths[1][0] := TPoint.Create(0,j,0);
        paths[2][0] := TPoint.Create(k,j,0);
        paths[3][0] := TPoint.Create(k,0,0);
        row:=original.ScanLine[0];  //pointe la premier ligne
            colors[1]:=BGR2RGB(row[0]);      //couleur premier colonne
            colors[2]:=BGR2RGB(row[k]);      //couleur derniere colonne
        row:=original.ScanLine[j];  //pointe la dernier ligne
            colors[0]:=BGR2RGB(row[0]);
            colors[3]:=BGR2RGB(row[k]);

    for i := 0 to 3 do
        begin
            strokes.add(Tstroke.Create(colors[i],paths[i]));{}
        end;
end;

procedure TMasterPiece.AppliquerFlou(rayon:integer);
begin
      reference.Canvas.Draw(0, 0, original);
      //tic:=Gettickcount;
      GBlur(reference, rayon);
      //AfficherTemps('Blurring', tic);
end;

function TMasterPiece.GetColor(image : TBitmap2; var x : integer; var y : integer) : TRGBA;
var
    row : PBGRs;
begin
    row:=image.ScanLine[image.Height-y-1];
    result := BGR2RGB(row[x]);
end;

function TMasterPiece.PeindreUneCouche(canvas : TGLFrame;  rayon : integer) : byte;
var
   x, y, xMax, yMax, error, tol : integer;
   path : TPath;
   color : TRGBA;
begin
    //try
      Diff(canvas);              // create a pointwise difference image
      x := rayon div 2;
      tol := 20;
      SetLength(path,200);
      while x <= difference.Width do
      begin
          y := rayon div 2;
          while y <= difference.height do
          begin
              error := 0;
              xMax := 0;
              yMax := 0;
              error := LocalError(x, y, xMax, yMax, rayon);
              if error > tol then
              begin
                  color := GetColor(reference, xMax, yMax);
                  path[0] := TPoint.Create(xMax,yMax,Random(3));
                  strokes.add(Tstroke.Create(color,path));
              end;
              inc(y,rayon);  //  grid := f g R
          end;
          inc(x,rayon);  //  grid := f g R
      end;
      {
          // find the largest error point
          (x1,y1) := arg maxi,j ,  M   Di,j
          s := makeStroke(R,x1,y1,referenceImage)
          add s to S
        end;
      end;
      paint all strokes in S on the canvas in random order

      result := 1;
    except
      ShowMessage('pas su peindre une couche');
      result := 0;
    end;}
end;

function TMasterPiece.Peindre(canvas : TGLFrame; rayon : array of integer): byte;
var
    i : integer;
begin
    reference := TBitmap2.Create;
    reference.CopyCanvas(original,true); // Copie du BitmpaOriginal dans BitmapDeReference
  //try
    for i:= 0 to Length(rayon)-1 do
    begin
        AppliquerFlou(rayon[i]);
        PeindreUneCouche(canvas,rayon[i]);
    end;
    result := 0;
  {Except
    ShowMessage('pas su peindre');
    result := 0;
  end;}
end;

end.
